<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
 * Помошник для работы с деревьями
 * 
 * @package CoreFramework
 * @version 1.0
 * @author Gennadiy Kozlenko
 */

/**
 * Построение дерева из массива
 *
 * @access public
 * @param array $array
 * @param string $element_name
 * @param string $parent_name
 * @return array
 */
function array_tree(&$array, $element_name, $parent_name) {
   // Строим массив, где ключ - идентификатор родительского элемента, а значение - массив дочерних элементов
   $list = array(0 => array());
   foreach ($array as $value) {
      if (empty($list[(int) $value[$parent_name]])) {
         $list[(int) $value[$parent_name]] = array();
      }
      array_push($list[(int) $value[$parent_name]], $value);
   }
   return _process_array_tree($list, $element_name, $parent_name);
} // end array_tree

/**
 * Рекурсивная функция процессинга массива для генерации дерева
 *
 * @access private
 * @param array $list
 * @param string $element_name
 * @param string $parent_name
 * @param integer $item
 * @return array
 */
function _process_array_tree(&$list, $element_name, $parent_name, $item = 0) {
   $tree = array();
   if (!isset($list[$item]) || !is_array($list[$item])) {
      return array();
   }
   foreach ($list[$item] as $val) {
      $node = $val;
      $node['child'] = _process_array_tree($list, $element_name, $parent_name, $val[$element_name]);
      array_push($tree, $node);
   }
   return $tree;
} // end _process_array_tree

/**
 * Сворачивание дерева в лист
 *
 * @access public
 * @param array $tree
 * @param string $level_element
 * @return array
 */
function collapse_tree(&$tree, $level_element = '', $level = 0) {
   $array = array();
   if (is_array($tree)) {
      foreach ($tree as $value) {
         if (is_array($value)) {
            if (!empty($level_element)) {
               $value[$level_element] = $level;
            }
            $child = array();
            if (isset($value['child'])) {
               if (is_array($value['child'])) {
                  $child = $value['child'];
               }
               unset($value['child']);
            }
            array_push($array, $value);
            if (0 < count($child)) {
               $array = array_merge($array, collapse_tree($child, $level_element, $level + 1));
            }
         }
      }
   }
   return $array;
} // end collapse_tree

/**
 * Построение пути к определенному элементу дерева
 *
 * @access public
 * @param array $tree
 * @param string $element_name
 * @param string $title_name
 * @param integer $id
 * @param string $separator
 * @return string
 */
function tree_path(&$tree, $element_name, $title_name, $id, $separator = ' > ') {
   $path = array();
   $array = array_reverse(collapse_tree($tree, 'level'));
   $is_write = false;
   $last_level = INF;
   foreach ($array as $value) {
      if (isset($value[$element_name]) && $id == $value[$element_name]) {
         $is_write = true;
      }
      if ($is_write && isset($value[$title_name])) {
         if ($value['level'] >= $last_level) {
            continue;
         }
         array_push($path, $value[$title_name]);
         $last_level = $value['level'];
      }
      if ($is_write && 0 == $value['level']) {
         break;
      }
   }
   return implode(array_reverse($path), $separator);
} // end tree_path

/**
 * Поиск в дереве по ключу/значению
 * Возвращает ветвь к элементу в котором поиск увенчался успехом
 *
 * @param array $tree
 * @param string $element_key
 * @param mixed $element_val
 * @return array
 */
function tree_search(&$tree, $element_key, $element_val) {
   $branch = array();
   foreach ($tree as $val) {
      if (isset($val[$element_key])) {
         if ($element_val == $val[$element_key]) {
            if (isset($val['child'])) {
               unset($val['child']);
            }
            return $val;
         } elseif (isset($val['child'])) {
            $array = tree_search($val['child'], $element_key, $element_val);
            if (0 < count($array)) {
               if (isset($val['child'])) {
                  unset($val['child']);
               }
               $branch = $val;
               $branch['child'] = $array;
            }
         }
      }
   }
   return $branch;
} // end tree_search

/**
 * Конвертирование ветви дерева (которое возвращается функцией tree_search) в полноценное дерево
 *
 * @param array $branch
 * @return array
 */
function branch_to_tree(&$branch) {
   $tree = array();
   if (isset($branch['child'])) {
      $child = $branch['child'];
      unset($branch['child']);
      $tree = $branch;
      $tree['child'] = branch_to_tree($child);
   } else {
      $tree = $branch;
      $tree['child'] = array();
   }
   return array($tree);
}

/**
 * Поиск в дереве по ключу/значению
 * Возвращает ветвь дочерних элементов элемента в котором поиск увенчался успехом
 *
 * @param array $tree
 * @param string $element_key
 * @param mixed $element_val
 * @return array
 */
function tree_search_child(&$tree, $element_key, $element_val) {
   foreach ($tree as $val) {
      if (isset($val[$element_key])) {
         if ($element_val == $val[$element_key]) {
            return $val;
         } elseif (isset($val['child'])) {
            $branch = tree_search_child($val['child'], $element_key, $element_val);
            if (!empty($branch)) {
               return $branch;
            }
         }
      }
   }
   return array();
} // end tree_search

